/* * Copyright 2013-2014 Odysseus Software GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.musicmount.fx; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import org.musicmount.util.LoggingUtil; import javafx.application.Platform; import javafx.scene.control.TextArea; /** * Redirect system out/err to text area. */ public class FXConsole { private static int BUFFER_SIZE = 8192; private static int MAX_TEXT_LEN = 1024 * 1024; private static int FLUSH_INTERVAL = 200; private final TextArea textArea; private final StringBuffer flushed = new StringBuffer(); private final Thread flushThread = new Thread(new Runnable() { @Override public void run() { while (running) { try { Thread.sleep(FLUSH_INTERVAL); appendFlushed(); } catch (InterruptedException | IOException e) { e.printStackTrace(); } } } }); private final OutputStream output = new OutputStream() { private final byte[] buffer = new byte[BUFFER_SIZE]; @Override public void write(int i) throws IOException { if (pos == BUFFER_SIZE) { flush(); } buffer[pos++] = (byte)i; } public void write(byte[] b, int off, int len) throws IOException { if (pos + len < BUFFER_SIZE) { System.arraycopy(b, off, buffer, pos, len); pos += len; } else { flush(); if (len < BUFFER_SIZE) { System.arraycopy(b, off, buffer, 0, len); } else { FXConsole.this.flush(b, off, len); } } } @Override public void flush() throws IOException { FXConsole.this.flush(buffer, 0, pos); pos = 0; } @Override public void close() throws IOException { flush(); } }; private int pos = 0; private boolean running = false; private PrintStream saveErr, saveOut; public FXConsole() { this(new TextArea()); } public FXConsole(TextArea textArea) { this.textArea = textArea; this.saveErr = System.err; this.saveOut = System.out; flushThread.setDaemon(true); } TextArea getTextArea() { return textArea; } public void start() { PrintStream printStream = new PrintStream(output, true) { @Override public void close() { super.close(); stop(); } }; System.setErr(printStream); System.setOut(printStream); LoggingUtil.updateConsoleHandlers(); running = true; flushThread.start(); } public void stop() { System.setErr(saveErr); System.setOut(saveOut); LoggingUtil.updateConsoleHandlers(); running = false; try { flushThread.join(); } catch (InterruptedException e) { } } void flush(byte[] b, int off, int len) { if (len > 0) { synchronized (flushed) { flushed.append(new String(b, off, len)); } } } void appendFlushed() throws IOException { synchronized (flushed) { if (flushed.length() > 0) { final String s = flushed.toString(); flushed.setLength(0); Platform.runLater(new Runnable() { public void run() { textArea.appendText(s); int textLength = textArea.getText().length(); if (textLength > MAX_TEXT_LEN) { textArea.setText(textArea.getText(textLength - MAX_TEXT_LEN / 2, textLength)); } } }); } } } }